package com.zj.thread.selfFuture;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class FutureInAction {

    public static void main(String[] args) {
//        testInvoke();
        testBlock();
        System.out.println("submit end");
    }

    static void testInvoke(){
        Future<Integer> invoke = new FutureInAction().invoke((String bb)->{
            System.out.println("task start");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bb.length();
        },"aaaaaaaaaaaaaa");
        System.out.println("submit start");
        System.out.println(invoke.get());
        while(!invoke.isDone()){ }
        System.out.println(invoke.get());
    }

    static void testBlock(){
        Future<Integer> invoke = new FutureInAction().block((String bb)->{
            System.out.println("task start");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return bb.length();
        },"aaaaaaaaaaaaaa");
        System.out.println("submit start");
        System.out.println(invoke.get());
    }



    <T,R> Future<T> invoke(Callable<T,R> callable,R r){
        AtomicReference<T> result=new AtomicReference<>();
        AtomicBoolean state=new AtomicBoolean(false);
        Thread t=new Thread(()->{
            T action = callable.action(r);
            result.set(action);
            state.set(true);
        });
        t.start();
        return new SimpleFuture<>(result,state);
    }

     <T,R> Future<T> block(Callable<T,R> callable,R r){
        AtomicReference<T> result=new AtomicReference<>();
        AtomicBoolean state=new AtomicBoolean(false);
        Thread t=new Thread(()->{
            T action = callable.action(r);
            result.set(action);
            state.set(true);
        });
        t.start();
        return new BlockFuture<>(result,state);
    }

    class SimpleFuture<T> implements Future<T>{
        AtomicReference<T> result;
        AtomicBoolean state;
        SimpleFuture(AtomicReference<T> result,AtomicBoolean state){
            this.result=result;
            this.state=state;
        }
        @Override
        public T get() {
            return result.get();
        }

        @Override
        public boolean isDone() {
            return state.get();
        }
    }

    class BlockFuture<T> implements Future<T>{
        AtomicReference<T> result;
        AtomicBoolean state;
        BlockFuture(AtomicReference<T> result,AtomicBoolean state){
            this.result=result;
            this.state=state;
        }

        @Override
        public T get() {
            while(!state.get()){
            }
            return result.get();
        }

        @Override
        public boolean isDone() {
            return state.get();
        }
    }

    interface Future<T> {
        T get();
        boolean isDone();
    }

    interface Callable<T,R>{
        T action(R r);
    }
}
